<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta name="description" content="Create instanced 3D models." />
    <meta name="cesium-sandcastle-labels" content="Development" />
    <title>Cesium Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/CesiumUnminified/Cesium.js"
      nomodule
    ></script>
    <script type="module" src="../load-cesium-es6.js"></script>
  </head>
  <body
    class="sandcastle-loading"
    data-sandcastle-bucket="bucket-requirejs.html"
  >
    <style>
      @import url(../templates/bucket.css);
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar"></div>
    <script id="cesium_sandcastle_script">
      function startup(Cesium) {
        "use strict";
        //Sandcastle_Begin
        const viewer = new Cesium.Viewer("cesiumContainer", {
          shouldAnimate: true,
        });
        const scene = viewer.scene;
        const context = scene.context;
        const camera = viewer.camera;
        scene.debugShowFramesPerSecond = true;

        const instancedArraysExtension = context._instancedArrays;
        let count = 1024;
        let spacing = 0.0002;
        let url = "../../SampleData/models/CesiumAir/Cesium_Air.glb";
        let useCollection = true;

        const centerLongitude = -75.61209431;
        const centerLatitude = 40.042530612;
        const height = 50.0;

        function orientCamera(center, radius) {
          const range = Math.max(radius, camera.frustum.near) * 2.0;
          const heading = Cesium.Math.toRadians(230.0);
          const pitch = Cesium.Math.toRadians(-20.0);
          camera.lookAt(
            center,
            new Cesium.HeadingPitchRange(heading, pitch, range)
          );
          camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
        }

        function createCollection(instances) {
          const collection = scene.primitives.add(
            new Cesium.ModelInstanceCollection({
              url: url,
              instances: instances,
            })
          );

          collection.readyPromise
            .then(function (collection) {
              // Play and loop all animations at half-speed
              collection.activeAnimations.addAll({
                multiplier: 0.5,
                loop: Cesium.ModelAnimationLoop.REPEAT,
              });
              orientCamera(
                collection._boundingSphere.center,
                collection._boundingSphere.radius
              );
            })
            .catch(function (error) {
              window.alert(error);
            });
        }

        function createModels(instances) {
          const points = [];
          let model;

          const length = instances.length;
          for (let i = 0; i < length; ++i) {
            const instance = instances[i];
            const modelMatrix = instance.modelMatrix;
            const translation = new Cesium.Cartesian3();
            Cesium.Matrix4.getTranslation(modelMatrix, translation);
            points.push(translation);

            model = scene.primitives.add(
              Cesium.Model.fromGltf({
                url: url,
                modelMatrix: modelMatrix,
              })
            );

            model.readyPromise
              .then(function (model) {
                // Play and loop all animations at half-speed
                model.activeAnimations.addAll({
                  multiplier: 0.5,
                  loop: Cesium.ModelAnimationLoop.REPEAT,
                });
              })
              .catch(function (error) {
                window.alert(error);
              });
          }

          model.readyPromise.then(function (model) {
            const boundingSphere = new Cesium.BoundingSphere();
            Cesium.BoundingSphere.fromPoints(points, boundingSphere);
            orientCamera(
              boundingSphere.center,
              boundingSphere.radius + model.boundingSphere.radius
            );
          });
        }

        function reset() {
          scene.primitives.removeAll();
          const instances = [];
          const gridSize = Math.sqrt(count);

          for (let y = 0; y < gridSize; ++y) {
            for (let x = 0; x < gridSize; ++x) {
              const longitude = centerLongitude + spacing * (x - gridSize / 2);
              const latitude = centerLatitude + spacing * (y - gridSize / 2);
              const position = Cesium.Cartesian3.fromDegrees(
                longitude,
                latitude,
                height
              );

              const heading = Math.random();
              const pitch = Math.random();
              const roll = Math.random();
              const scale = (Math.random() + 1.0) / 2.0;

              const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
                position,
                new Cesium.HeadingPitchRoll(heading, pitch, roll)
              );
              Cesium.Matrix4.multiplyByUniformScale(
                modelMatrix,
                scale,
                modelMatrix
              );

              instances.push({
                modelMatrix: modelMatrix,
              });
            }
          }

          if (useCollection) {
            createCollection(instances);
          } else {
            createModels(instances);
          }
        }

        // Scale picked instances
        const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
        handler.setInputAction(function (movement) {
          const pickedInstance = scene.pick(movement.position);
          if (Cesium.defined(pickedInstance)) {
            console.log(pickedInstance);
            const instance = useCollection
              ? pickedInstance
              : pickedInstance.primitive;
            const scaleMatrix = Cesium.Matrix4.fromUniformScale(1.1);
            const modelMatrix = Cesium.Matrix4.multiply(
              instance.modelMatrix,
              scaleMatrix,
              new Cesium.Matrix4()
            );
            instance.modelMatrix = modelMatrix;
          }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        Sandcastle.addToolbarMenu([
          {
            text: "1024 instances",
            onselect: function () {
              count = 1024;
              reset();
            },
          },
          {
            text: "100 instances",
            onselect: function () {
              count = 100;
              reset();
            },
          },
          {
            text: "25 instances",
            onselect: function () {
              count = 25;
              reset();
            },
          },
          {
            text: "4 instances",
            onselect: function () {
              count = 4;
              reset();
            },
          },
          {
            text: "10000 instances",
            onselect: function () {
              count = 10000;
              reset();
            },
          },
        ]);

        Sandcastle.addToolbarMenu([
          {
            text: "Aircraft",
            onselect: function () {
              url = "../../SampleData/models/CesiumAir/Cesium_Air.glb";
              spacing = 0.0002;
              reset();
            },
          },
          {
            text: "Ground Vehicle",
            onselect: function () {
              url = "../../SampleData/models/GroundVehicle/GroundVehicle.glb";
              spacing = 0.00008;
              reset();
            },
          },
          {
            text: "Milk Truck",
            onselect: function () {
              url =
                "../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb";
              spacing = 0.00008;
              reset();
            },
          },
          {
            text: "Skinned Character",
            onselect: function () {
              url = "../../SampleData/models/CesiumMan/Cesium_Man.glb";
              spacing = 0.00001;
              reset();
            },
          },
        ]);

        Sandcastle.addToolbarMenu([
          {
            text: "Instancing Enabled",
            onselect: function () {
              context._instancedArrays = instancedArraysExtension;
              useCollection = true;
              reset();
            },
          },
          {
            text: "Instancing Disabled",
            onselect: function () {
              context._instancedArrays = undefined;
              useCollection = true;
              reset();
            },
          },
          {
            text: "Individual models",
            onselect: function () {
              useCollection = false;
              reset();
            },
          },
        ]);

        Sandcastle.addToolbarButton("2D", function () {
          scene.morphTo2D(0.0);
        });

        Sandcastle.addToolbarButton("CV", function () {
          scene.morphToColumbusView(0.0);
        });

        Sandcastle.addToolbarButton("3D", function () {
          scene.morphTo3D(0.0);
        });

        //Sandcastle_End
        Sandcastle.finishedLoading();
      }
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        startup(Cesium);
      }
    </script>
  </body>
</html>
